<script setup lang="ts">
import {computed, ref, watch, nextTick} from "vue";
import ResponseResult from "@models/ReturnResult.js";
import {isNull} from "@utils/stringUtil.js";
import axiosInstance from "@utils/axiosInstance.js";
import {globalConst} from "@constants/globalConst.js";
import {useGlobalConfirm} from "@utils/ConfirmDialogPlugin.js";

interface FileItem {
  file: File | null;
  customName: string;
  originalName: string;
}

const props = withDefaults(defineProps<{
  /**
   * 需要的文件数量
   */
  size?: string;
  /**
   * 上传图片的位置(自带后端接口前缀)
   */
  UPURl?: string;
  /**
   * 回调方法,将在返回成功时被调用
   * @param response
   */
  onUploadSuccess?: (response: ResponseResult<any>) => void;
  /**
   * 错误时的回调方法
   */
  onUploadError?: (response: ResponseResult<any>) => void;
  /**
   * 是否手动上传
   */
  OffAutomaticUpload?: boolean;
  /**
   * FormData额外参数信息
   */
  formDataMsg?: Map<string, string>;
  /**
   * 允许的文件类型
   */
  accept?: string;
}>(), {
  size: "1",
  UPURl: "user/resources/addFile/rar",
  OffAutomaticUpload: false,
  accept: "*/*",
});

const getSize = computed(() => Number.parseInt(props.size) || 1);
const needSelfDefiningTerm = ref(false);
const fileItems = ref<FileItem[]>([]);
const fileInputs = ref<HTMLInputElement[]>([]); // 新增：引用文件输入框
const isUploading = ref(false);
const uploadProgress = ref(0);

// 计算属性
const hasValue = computed(() => {
  return fileItems.value.some(item => item.file !== null);
});

const totalFileSize = computed(() => {
  return fileItems.value.reduce((total, item) => {
    return total + (item.file?.size || 0);
  }, 0);
});

const canUpload = computed(() => {
  return hasValue.value && !isUploading.value;
});

// 初始化文件项
const initializeFileItems = () => {
  fileItems.value = Array.from({length: getSize.value}, () => ({
    file: null,
    customName: "",
    originalName: ""
  }));
  // 重置所有文件输入框
  nextTick(() => {
    fileInputs.value.forEach(input => {
      if (input) input.value = "";
    });
  });
};

// 监听文件数量变化
watch(getSize, initializeFileItems, {immediate: true});

// 文件选择处理
const handleFileSelect = (event: Event, index: number) => {
  const input = event.target as HTMLInputElement;
  if (input.files && input.files[0]) {
    const file = input.files[0];

    // 文件大小检查 (2GB)
    if (file.size > 2 * 1024 * 1024 * 1024) {
      alert(`文件 "${file.name}" 大小超过2GB，请重新选择`);
      input.value = "";
      return;
    }

    fileItems.value[index] = {
      file,
      customName: fileItems.value[index]?.customName || file.name.split('.')[0],
      originalName: file.name
    };
  }
};

// 自定义文件名处理
const handleCustomNameChange = (value: string, index: number) => {
  if (fileItems.value[index]) {
    fileItems.value[index].customName = value;
  }
};

// 移除文件
async function removeFile(index: number) {
  const item = fileItems.value[index];
  if (!item.file) return;
  const com = useGlobalConfirm()
  const confirmed = await com("确定要移除这个文件吗?", {
    text: `文件: ${item.originalName}\n大小: ${(item.file.size / (1024 * 1024)).toFixed(2)} MB`,
    trueText: '确认移除',
    falseText: '取消'
  });
  if (!confirmed)
    return
  fileItems.value[index] = {
    file: null,
    customName: "",
    originalName: ""
  };
  // 重置对应的文件输入框
  await nextTick(() => {
    if (fileInputs.value[index]) {
      fileInputs.value[index].value = "";
    }
  });
};

// 设置文件输入框引用
const setFileInputRef = (el: HTMLInputElement, index: number) => {
  fileInputs.value[index] = el;
};

// 上传文件
async function uploadFile() {
  if (!hasValue.value) {
    alert('请选择要上传的文件');
    return;
  }
  if (totalFileSize.value > 1024 * 1024 * 1024 * 10) {
    alert('请不要单次上传10BG以上文件');
    return;
  }
  isUploading.value = true;
  uploadProgress.value = 0;
  try {
    const formData = new FormData();
    let validFileCount = 0;
    let i1 = []
    // 构建 FormData
    for (let i = 0; i < fileItems.value.length; i++) {
      const item = fileItems.value[i];
      if (item.file) {
        validFileCount++;
        formData.append("fileList", item.file);
        if (item.file.size > 2 * 1024 * 1024 * 1024) {
          alert(`文件 "${item.file.name}" 大小超过2GB，请重新选择`);
          return;
        }
        let fileName
        if (needSelfDefiningTerm.value && !isNull(item.customName)) {
          fileName = item.customName
        } else {
          fileName = item.originalName
        }
        i1.push(fileName)
        formData.append("fileName", fileName);
      }
    }
    formData.append("fileSize", String(validFileCount));
    let fileListText = '您上传的文件列表如下:\n'
    let i3 = 0
    for (let i of i1) {
      i3++
      fileListText += `{${i}}`
      if (i3 % 3 == 0) fileListText += '\n'
    }
    const com = useGlobalConfirm()
    const r = await com("确定要上传这些文件吗?", {
      text: `即将上传${validFileCount}个文件，总大小:${(totalFileSize.value / (1024 * 1024)).toFixed(2)}MB\n\n在继续前请确认:\n• 文件是否齐全\n• 文件是否包含拓展名\n• 文件拓展名是否齐全\n\n${fileListText}`,
      trueText: '确认无误',
      falseText: '我需要修改'
    })
    if (!r)
      return
    // 添加额外参数
    if (props.formDataMsg) {
      props.formDataMsg.forEach((value, key) => {
        formData.append(key, value);
      });
    }

    const url = !isNull(props.UPURl) ? props.UPURl : "user/resources/addFile/rar";

    const response = await axiosInstance.post(
        `${globalConst.baseUrl}${url}`,
        formData,
        {
          headers: {
            'Content-Type': 'multipart/form-data',
          },
          onUploadProgress: (progressEvent) => {
            if (progressEvent.total) {
              uploadProgress.value = Math.round(
                  (progressEvent.loaded * 100) / progressEvent.total
              );
            }
          }
        }
    );

    const result = ResponseResult.fromApiResponse(response.data);

    if (result.isSuccess()) {
      alert('文件上传成功!' + result.msg);
      props.onUploadSuccess?.(result);
      // 上传成功后清空文件列表
      initializeFileItems();
    } else {
      alert(`文件上传失败: ${result.msg || '未知错误!'}`);
    }
  } finally {
    isUploading.value = false;
    uploadProgress.value = 0;
  }
}

// 重置表单
async function resetForm() {
  const com = useGlobalConfirm()
  const r = await com("确定要清空选择吗", {
    trueText: '是的,我确定',
    falseText: '取消清空'
  })
  if (!r)
    return
  initializeFileItems();
  uploadProgress.value = 0;
}

// 暴露方法给父组件
defineExpose({
  uploadFile,
  resetForm,
  getFileList: () => fileItems.value.filter(item => item.file).map(item => item.file!)
});
</script>

<template>
  <div class="file-upload-container">
    <!-- 配置选项 -->
    <div class="upload-config">
      <label class="config-item">
        <input
            type="checkbox"
            v-model="needSelfDefiningTerm"
            class="checkbox"
        >
        <span class="config-label">自定义文件名</span>
      </label>
      <hr>
      <p class="tip">上传注意事项：</p>
      <p class="tip">1.由于服务器很烂,单个文件大小不能超过2GB,不然服务器顶不住</p>
      <p class="tip">
        2.如果是带分卷压缩包的压缩包文件,在自定义文件名时需要手动写上拓展名,不然服务器将无法识别分卷文件</p>
      <p class="tip">
        3.一次最多上传10GB文件,不然服务器顶不住</p>
    </div>
  </div>

  <!-- 上传区域 -->
  <main class="upload-main">
    <div
        v-for="(item, index) in fileItems"
        :key="index"
        class="file-item"
    >
      <div class="file-input-group">
        <!-- 自定义文件名输入 -->
        <div v-if="needSelfDefiningTerm" class="input-file-name">
          <label class="input-label">文件名:</label>
          <input
              type="text"
              :value="item.customName"
              @input="handleCustomNameChange(($event.target as HTMLInputElement).value, index)"
              placeholder="请输入文件名"
              class="name-input"
              :disabled="!item.file"
          >
        </div>

        <!-- 文件选择 -->
        <div class="file-selector">
          <label class="input-label">文件:</label>
          <div class="file-input-wrapper">
            <input
                type="file"
                @change="handleFileSelect($event, index)"
                :accept="accept"
                class="file-input"
                :ref="el => setFileInputRef(el as HTMLInputElement, index)"
            >
            <span class="file-name" v-if="item.file">
                {{ item.originalName }}
              </span>
            <button
                v-if="item.file"
                @click="removeFile(index)"
                type="button"
                class="remove-btn"
                title="移除文件"
            >
              ×
            </button>
          </div>
        </div>

        <!-- 文件信息 -->
        <div v-if="item.file" class="file-info">
            <span class="file-size">
              大小: {{ (item.file.size / (1024 * 1024)).toFixed(2) }} MB
            </span>
        </div>
      </div>
    </div>

    <!-- 上传按钮和进度 -->
    <div class="upload-controls">
      <button
          @click="uploadFile"
          :disabled="!canUpload"
          class="upload-btn"
          :class="{ 'uploading': isUploading }">
        <span v-if="isUploading">上传中...</span>
        <span v-else-if="!props.OffAutomaticUpload">提交文件</span>
      </button>
      <button
          @click="resetForm"
          type="button"
          class="reset-btn"
          :disabled="isUploading"
      >
        重置
      </button>
      <!-- 上传进度 -->
      <div v-if="isUploading" class="upload-progress">
        <div class="progress-bar">
          <div
              class="progress-fill"
              :style="{ width: uploadProgress + '%' }"
          ></div>
        </div>
        <span class="progress-text">{{ uploadProgress }}%</span>
      </div>
      <!-- 总文件大小 -->
      <div v-if="hasValue" class="total-size">
        总大小: {{ (totalFileSize / (1024 * 1024)).toFixed(2) }} MB
      </div>
    </div>
  </main>
</template>

<style scoped>
.file-upload-container {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

.upload-config {
  margin-bottom: 20px;
  padding: 15px;
  background: #f5f5f5;
  border-radius: 8px;
}

.config-item {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
  cursor: pointer;
}

.checkbox {
  margin-right: 8px;
}

.config-label {
  font-weight: 500;
}

.tip {
  margin: 0;
  font-size: 12px;
  color: #666;
  line-height: 1.4;
}

.upload-main {
  space-y: 16px;
}

.file-item {
  margin-bottom: 20px;
  padding: 16px;
  border: 1px solid #e1e1e1;
  border-radius: 8px;
  background: #fff;
}

.file-input-group {
  space-y: 12px;
}

.input-file-name,
.file-selector {
  display: flex;
  align-items: center;
  gap: 12px;
}

.input-label {
  min-width: 60px;
  font-weight: 500;
  color: #333;
}

.name-input {
  flex: 1;
  padding: 8px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.name-input:disabled {
  background-color: #f5f5f5;
  color: #999;
}

.file-input-wrapper {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
}

.file-input {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.file-name {
  flex: 1;
  font-size: 14px;
  color: #333;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.remove-btn {
  width: 24px;
  height: 24px;
  border: none;
  background: #ff4757;
  color: white;
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.remove-btn:hover {
  background: #ff3742;
}

.file-info {
  margin-top: 8px;
}

.file-size {
  font-size: 12px;
  color: #666;
}

.upload-controls {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid #e1e1e1;
  space-y: 12px;
}

.upload-btn,
.reset-btn {
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
  margin-right: 12px;
}

.upload-btn {
  background: #1890ff;
  color: white;
}

.upload-btn:hover:not(:disabled) {
  background: #40a9ff;
}

.upload-btn:disabled {
  background: #ccc;
  cursor: not-allowed;
}

.upload-btn.uploading {
  background: #faad14;
}

.reset-btn {
  background: #f5f5f5;
  color: #666;
  border: 1px solid #ddd;
}

.reset-btn:hover:not(:disabled) {
  background: #e1e1e1;
}

.reset-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.upload-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
}

.progress-bar {
  flex: 1;
  height: 8px;
  background: #f0f0f0;
  border-radius: 4px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: #52c41a;
  transition: width 0.3s ease;
}

.progress-text {
  font-size: 12px;
  color: #666;
  min-width: 40px;
}

.total-size {
  font-size: 12px;
  color: #666;
  text-align: center;
  margin-top: 8px;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .file-upload-container {
    padding: 16px;
  }

  .input-file-name,
  .file-selector {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }

  .input-label {
    min-width: auto;
  }
}
</style>
